hvm: hpet: Fix overflow when converting to nanoseconds.
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 8 Jan 2008 16:20:04 +0000 (16:20 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 8 Jan 2008 16:20:04 +0000 (16:20 +0000)
Currently in hpet_tick_to_ns, the approach is multiplying first, which
easily causes overflow when tick is quite large. The patch cannot
handle arbitratry large ticks duo to the precision requirement and
64bit's value range. But by optimize the equation, a larger ticks than
current code can be supported. Also an overflow check is added before
the calculation.

From: Haitao Shan <haitao.shan@intel.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/hvm/hpet.c
xen/include/asm-x86/hvm/vpt.h

index 603ffe891568be3a12d3ec25415996522802dcca..14f525893f352d18f6b646c56d651247654728a0 100644 (file)
@@ -71,8 +71,9 @@
 #define HPET_TN_INT_ROUTE_CAP_MASK (0xffffffffULL \
                     << HPET_TN_INT_ROUTE_CAP_SHIFT)
 
-#define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)* \
-                                  (S_TO_NS*TSC_PER_HPET_TICK)/h->tsc_freq)
+#define hpet_tick_to_ns(h, tick)                        \
+    ((s_time_t)((((tick) > (h)->hpet_to_ns_limit) ?     \
+        ~0ULL : (tick) * (h)->hpet_to_ns_scale) >> 10))
 
 #define timer_config(h, n)       (h->hpet.timers[n].config)
 #define timer_is_periodic(h, n)  (timer_config(h, n) & HPET_TN_PERIODIC)
@@ -537,6 +538,9 @@ void hpet_init(struct vcpu *v)
     h->vcpu = v;
     h->tsc_freq = ticks_per_sec(v);
 
+    h->hpet_to_ns_scale = ((S_TO_NS * TSC_PER_HPET_TICK) << 10) / h->tsc_freq;
+    h->hpet_to_ns_limit = (~0ULL >> 1) / h->hpet_to_ns_scale;
+
     /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
     h->hpet.capability = 0x8086A201ULL;
 
index df54f66268709cb81d7cc5cb4a92ab780c2d3910..b7176e89b192faab4c5b844ddf588a32b95b7309 100644 (file)
@@ -58,6 +58,8 @@ typedef struct HPETState {
     struct hpet_registers hpet;
     struct vcpu *vcpu;
     uint64_t tsc_freq;
+    uint64_t hpet_to_ns_scale; /* hpet ticks to ns (multiplied by 2^10) */
+    uint64_t hpet_to_ns_limit; /* max hpet ticks convertable to ns      */
     uint64_t mc_offset;
     struct timer timers[HPET_TIMER_NUM];
     struct HPET_timer_fn_info timer_fn_info[HPET_TIMER_NUM];